package edu.washington.ling.syntric.struct.tree;

import java.util.List;
import java.util.LinkedList;
import java.util.HashMap;
import java.util.Map;

import edu.washington.ling.syntric.struct.projection.ProjectionNode;


public class Token extends Node {
	private Token dsHead;
	private List<Token> pbHeads;
	private List<Token> dsDependents;
	private List<Token> ecDependents;
	private List<Token> pbArguments;
	private Map<String, List<ProjectionNode>> psProjForestMap;
	private boolean isDSEmptyCategory;
	private boolean isPSEmptyCategory;
	
	public Token() {
		super();
		dsHead = null;
		pbHeads = new LinkedList<Token>();
		dsDependents = new LinkedList<Token>();
		ecDependents = new LinkedList<Token>();
		pbArguments = new LinkedList<Token>();
		psProjForestMap = new HashMap<String, List<ProjectionNode>>();
		isDSEmptyCategory = false;
		isPSEmptyCategory = false;
	}
	public Token(Token t) {
		super(t);
		dsHead = null;
		pbHeads = new LinkedList<Token>();
		dsDependents = new LinkedList<Token>();
		ecDependents = new LinkedList<Token>();
		pbArguments = new LinkedList<Token>();
		psProjForestMap = new HashMap<String, List<ProjectionNode>>();
		isDSEmptyCategory = t.isDSEmptyCategory();
		isPSEmptyCategory = t.isPSEmptyCategory();
	}
	public void setName(String s){
		super.featureMap.put("name", s);
	}
	public boolean hasName(){
		return (super.featureMap.containsKey("name"));
	}	
	public String getName(){
		return super.featureMap.get("name");
	}
	public void setWord(String s){
		super.derrivedFeatures.add("word");
		super.featureMap.put("word", s);
	}
	public String getWord(){
		return super.featureMap.get("word");
	}
	public void setTag(String s){
		super.derrivedFeatures.add("tag");
		super.featureMap.put("tag", s);
	}
	public String getTag(){
		return super.featureMap.get("tag");
	}
	public void setDSRelation(String relation){
		super.derrivedFeatures.add("reltype");
		super.featureMap.put("reltype", relation);
	}
	public boolean hasDSRelation(){
		return (super.featureMap.containsKey("reltype"));
	}
	public String getDSRelation(){
		return super.featureMap.get("reltype");
	}
	public void setDSHead(Token head){
		dsHead = head;
	}
	public boolean hasDSHead(){
		return (dsHead != null);
	}
	public Token getDSHead(){
		return dsHead;
	}
	public void addDSDependent(Token dependent){
		dsDependents.add(dependent);
	}
	public boolean hasDSDependents() {
		return (dsDependents.size() > 0);
	}
	public List<Token> getDSDependents(){
		return dsDependents;
	}
	public void setDSDependents(List<Token> dependents) {
		dsDependents = dependents;
	}
	public void removeDSDependent(Token dependent) {
		dsDependents.remove(dependent);
	}
	public void addECDependent(Token dependent) {
		ecDependents.add(dependent);
	}
	public void setECDependents(List<Token> dependents) {
		ecDependents = new LinkedList<Token>(dependents);
	}
	public List<Token> getECDependents() {
		return ecDependents;
	}
	public void removeECDependents() {
		ecDependents.clear();
	}
	public void addPBHead(Token head, String argumentType) {
		super.derrivedFeatures.add("argtype_" + head.getName());
		super.featureMap.put("argtype_" + head.getName(), argumentType);
		pbHeads.add(head);
	}
	public boolean hasPBHeads() {
		return pbHeads.size() > 0;
	}
	public List<Token> getPBHeads() {
		return pbHeads;
	}
	public boolean hasPBArgumentType(Token head) {
		return super.featureMap.containsKey("argtype_" + head.getName());
	}
	public String getPBArgumentType(Token head) {
		return super.featureMap.get("argtype_" + head.getName());
	}
	public void addPBArgument(Token argument) {
		pbArguments.add(argument);
	}
	public boolean hasPBArguments() {
		return pbArguments.size() > 0;
	}
	public List<Token> getPBArguments() {
		return pbArguments;
	}
	public void setAsDSDEmptyCategory() {
		this.isDSEmptyCategory = true;
	}
	public void setAsPSEmptyCategory() {
		this.isPSEmptyCategory = true;
	}
	public boolean isDSEmptyCategory() {
		return this.isDSEmptyCategory;
	}
	public boolean isPSEmptyCategory() {
		return this.isPSEmptyCategory;
	}
	public boolean isEmptyCategory() {
		return (this.isDSEmptyCategory || this.isPSEmptyCategory);
	}
	public void addChainsToProjForest(List<ProjectionNode> projChains) {
		for (ProjectionNode projChain: projChains) {
			String label = projChain.getRootLabel();
			if (psProjForestMap.containsKey(label)) {
				psProjForestMap.get(label).add(projChain);
			}
			else {
				List<ProjectionNode> projForestForLabel = new LinkedList<ProjectionNode>();
				projForestForLabel.add(projChain);
				psProjForestMap.put(label, projForestForLabel);
			}
		}
	}
	
	

	public void setDSSourceIndex(int index) {
		super.featureMap.put("index", Integer.toString(index));
	}
	public void setDSTargetIndex(int tindex) {
		super.featureMap.put("tindex", Integer.toString(tindex));
	}

	public boolean isScrambledOverModifier() {
		boolean scrOverMod = false;
		if (super.featureMap.containsKey("scr-mod")) {
			scrOverMod = Boolean.parseBoolean(super.featureMap.get("scr-mod"));
		}
		return scrOverMod;
	}
	public void setScrambledOverModifier(boolean scrOverMod) {
		super.featureMap.put("scr-mod", Boolean.toString(scrOverMod));
	}
	public boolean isScrambledOverArgument() {
		boolean scrOverArg = false;
		if (super.featureMap.containsKey("scr-arg")) {
			scrOverArg = Boolean.parseBoolean(super.featureMap.get("scr-arg"));
		}
		return scrOverArg;
	}
	public void setScrambledOverArgument(boolean scrOverArg) {
		super.featureMap.put("scr-arg", Boolean.toString(scrOverArg));
	}
	public boolean isScrambledLongDistance() {
		boolean scrLongDist = false;
		if (super.featureMap.containsKey("scr-long")) {
			scrLongDist = Boolean.parseBoolean(super.featureMap.get("scr-long"));
		}
		return scrLongDist;
	}
	public void setScrambledLongDistance(boolean scrLongDist) {
		super.featureMap.put("scr-long", Boolean.toString(scrLongDist));
	}
	
	public boolean isExtraposed() {
		boolean extraposed = false;
		if (super.featureMap.containsKey("extr")) {
			extraposed = Boolean.parseBoolean(super.featureMap.get("extr"));
		}
		return extraposed;
	}
	public void setExtraposed(boolean extraposed) {
		super.featureMap.put("extr", Boolean.toString(extraposed));
	}
	
	
	public boolean hasProjForestWithLabel(String label) {
		return psProjForestMap.containsKey(label);
	}
	public List<ProjectionNode> getProjForestWithLabel(String label) {
		return psProjForestMap.get(label);
	}
	public List<ProjectionNode> getProjForest() {
		List<ProjectionNode> projForest = new LinkedList<ProjectionNode>();
		for (List<ProjectionNode> subForest: psProjForestMap.values()) {
			projForest.addAll(subForest);
		}
		return projForest;
	}
	public void setProjForest(List<ProjectionNode> projChains) {
		psProjForestMap.clear();
		addChainsToProjForest(projChains);
	}

}
